package com.tanhua.dubbo.api.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import com.tanhua.dubbo.api.UserLikeApi;
import com.tanhua.dubbo.pojo.UserLike;
import org.apache.dubbo.config.annotation.DubboService;
import org.bson.types.ObjectId;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.data.redis.core.StringRedisTemplate;

import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * 对于用户喜欢或不喜欢的操作，数据要存储到Redis和MongoDB中
 */
@DubboService(version = "1.0.0")
public class UserLikeApiImpl implements UserLikeApi {

    public static final String LIKE_REDIS_KEY_PREFIX = "USER_LIKE_";

    public static final String NOT_LIKE_REDIS_KEY_PREFIX = "USER_NOT_LIKE_";

    @Autowired
    private MongoTemplate mongoTemplate;

    @Autowired
    private StringRedisTemplate redisTemplate;


    /**
     * 喜欢
     *
     * @param userId
     * @param likeUserId
     * @return
     */
    @Override
    public Boolean likeUser(Long userId, Long likeUserId) {
        //判断是否已经喜欢
        if (this.isLike(userId, likeUserId)) {
            return false;
        }

        //保存到MongoDB
        this.saveMongoDB(userId, likeUserId, true);

        //写入到Redis中，采用hash结构
        //1喜欢2， 大key: USER_LIKE_1；小key："2" ； 值："1"
        //1喜欢3， 大key: USER_LIKE_1；小key："3" ； 值："1"
        //1不喜欢4， 大key: USER_NOT_LIKE_1；小key："4" ； 值："1"

        String redisKey = getLikeRedisKey(userId);
        this.redisTemplate.opsForHash().put(redisKey, Convert.toStr(likeUserId), "1");
        //将喜欢的用户从不喜欢的列表中移除
        String notLikeRedisKey = getNotLikeRedisKey(userId);
        this.redisTemplate.opsForHash().delete(notLikeRedisKey, Convert.toStr(likeUserId));

        return true;
    }

    private void saveMongoDB(Long userId, Long likeUserId, boolean isLike) {
        Query query = Query.query(Criteria.where("userId").is(userId).and("likeUserId").is(likeUserId));
        UserLike userLike = this.mongoTemplate.findOne(query, UserLike.class);
        if (userLike != null) {
            //更新
            Update update = Update.update("isLike", isLike)
                    .set("updated", System.currentTimeMillis());
            this.mongoTemplate.updateFirst(query, update, UserLike.class);
        } else {
            userLike = new UserLike();
            userLike.setId(ObjectId.get());
            userLike.setUserId(userId);
            userLike.setLikeUserId(likeUserId);
            userLike.setIsLike(isLike);
            userLike.setCreated(System.currentTimeMillis());
            userLike.setUpdated(userLike.getCreated());
            this.mongoTemplate.save(userLike);
        }
    }

    private String getLikeRedisKey(Long userId) {
        return LIKE_REDIS_KEY_PREFIX + userId;
    }

    private String getNotLikeRedisKey(Long userId) {
        return NOT_LIKE_REDIS_KEY_PREFIX + userId;
    }

    /**
     * 不喜欢
     *
     * @param userId
     * @param likeUserId
     * @return
     */
    @Override
    public Boolean notLikeUser(Long userId, Long likeUserId) {
        //判断是否已经不喜欢
        if (this.isNotLike(userId, likeUserId)) {
            return false;
        }

        //保存到MongoDB
        this.saveMongoDB(userId, likeUserId, false);

        String notLikeRedisKey = getNotLikeRedisKey(userId);
        this.redisTemplate.opsForHash().put(notLikeRedisKey, Convert.toStr(likeUserId), "1");
        //将不喜欢的用户从喜欢的列表中移除
        String likeRedisKey = getLikeRedisKey(userId);
        this.redisTemplate.opsForHash().delete(likeRedisKey, Convert.toStr(likeUserId));

        return true;
    }

    @Override
    public Boolean isLike(Long userId, Long likeUserId) {
        String redisKey = getLikeRedisKey(userId);
        return this.redisTemplate.opsForHash().hasKey(redisKey, Convert.toStr(likeUserId));
    }

    @Override
    public Boolean isNotLike(Long userId, Long likeUserId) {
        String redisKey = getNotLikeRedisKey(userId);
        return this.redisTemplate.opsForHash().hasKey(redisKey, Convert.toStr(likeUserId));
    }

    @Override
    public Boolean isMutualLike(Long userId, Long likeUserId) {
        return this.isLike(userId, likeUserId) && this.isLike(likeUserId, userId);
    }

    @Override
    public List<Long> queryLikeList(Long userId) {
        String redisKey = getLikeRedisKey(userId);
        Set<Object> keys = this.redisTemplate.opsForHash().keys(redisKey);
        if (CollUtil.isEmpty(keys)) {
            return Collections.emptyList();
        }
        return keys.stream().map(o -> Convert.toLong(o)).collect(Collectors.toList());
    }

    @Override
    public List<Long> queryNotLikeList(Long userId) {
        String redisKey = getNotLikeRedisKey(userId);
        Set<Object> keys = this.redisTemplate.opsForHash().keys(redisKey);
        if (CollUtil.isEmpty(keys)) {
            return Collections.emptyList();
        }
        return keys.stream().map(o -> Convert.toLong(o)).collect(Collectors.toList());
    }
}
